/* * Copyright 2013 NGDATA nv * Copyright 2007 Outerthought bvba and Schaubroeck nv * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.lilyproject.runtime.module.build; import java.util.HashMap; import java.util.Map; import org.apache.commons.jxpath.JXPathContext; import org.lilyproject.runtime.LilyRTException; import org.lilyproject.runtime.conf.Conf; import org.lilyproject.runtime.model.JavaServiceInjectDefinition; import org.lilyproject.runtime.module.javaservice.JavaServiceManager; import org.lilyproject.runtime.rapi.ConfRegistry; import org.lilyproject.runtime.rapi.LilyRuntimeModule; import org.lilyproject.runtime.rapi_impl.LilyRuntimeModuleImpl; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.NamespaceHandler; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; import org.w3c.dom.Node; public class LilyRuntimeNamespaceHandler implements NamespaceHandler { public void init() { } public BeanDefinition parse(Element element, ParserContext parserContext) { SpringBuildContext springBuildContext = ModuleBuilder.SPRING_BUILD_CONTEXT.get(); String elementName = element.getLocalName(); ElementProcessor processor = ELEMENT_PROCESSORS.get(elementName); if (processor != null) { try { return processor.process(element, parserContext, springBuildContext); } catch (Throwable e) { throw new LilyRTException("Error handling " + elementName + " directive.", e); } } return null; } public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder beanDefinitionHolder, ParserContext parserContext) { return null; } private static interface ElementProcessor { BeanDefinition process(Element element, ParserContext parserContext, SpringBuildContext springBuildContext) throws Exception; } private static final ElementProcessor MODULE_PROCESSOR = new ElementProcessor() { public BeanDefinition process(Element element, ParserContext parserContext, SpringBuildContext springBuildContext) { String classLoaderBeanId = element.getAttribute("classLoader"); if (classLoaderBeanId.length() > 0) { RootBeanDefinition def = new RootBeanDefinition(ObjectFactoryBean.class); ConstructorArgumentValues args = new ConstructorArgumentValues(); args.addIndexedArgumentValue(0, ClassLoader.class); args.addIndexedArgumentValue(1, springBuildContext.getModuleClassLoader()); def.setConstructorArgumentValues(args); def.setLazyInit(false); parserContext.getRegistry().registerBeanDefinition(classLoaderBeanId, def); } String handleBeanId = element.getAttribute("handle"); if (handleBeanId.length() > 0) { RootBeanDefinition def = new RootBeanDefinition(ObjectFactoryBean.class); ConstructorArgumentValues args = new ConstructorArgumentValues(); args.addIndexedArgumentValue(0, LilyRuntimeModule.class); args.addIndexedArgumentValue(1, new LilyRuntimeModuleImpl(springBuildContext.getModule(), springBuildContext.getRuntime())); def.setConstructorArgumentValues(args); def.setLazyInit(false); parserContext.getRegistry().registerBeanDefinition(handleBeanId, def); } String confBeanId = element.getAttribute("conf"); if (confBeanId.length() > 0) { RootBeanDefinition def = new RootBeanDefinition(ObjectFactoryBean.class); String moduleId = springBuildContext.getModule().getDefinition().getId(); ConfRegistry confRegistry = springBuildContext.getRuntime().getConfManager().getConfRegistry(moduleId); ConstructorArgumentValues args = new ConstructorArgumentValues(); args.addIndexedArgumentValue(0, ConfRegistry.class); args.addIndexedArgumentValue(1, confRegistry); def.setConstructorArgumentValues(args); def.setLazyInit(false); parserContext.getRegistry().registerBeanDefinition(confBeanId, def); } return null; } }; private static final ElementProcessor IMPORT_SERVICE_PROCESSOR = new ElementProcessor() { public BeanDefinition process(Element element, ParserContext parserContext, SpringBuildContext springBuildContext) throws ClassNotFoundException { String service = element.getAttribute("service"); Class serviceClass = parserContext.getReaderContext().getBeanClassLoader().loadClass(service); JavaServiceManager javaServiceManager = springBuildContext.getRuntime().getJavaServiceManager(); String id = element.getAttribute("id"); String dependencyName = element.getAttribute("name"); if (dependencyName.equals("")) { dependencyName = id; } Object component; try { JavaServiceInjectDefinition injectDef = springBuildContext.getModule().getDefinition().getJavaServiceInject(dependencyName); if (injectDef == null) { injectDef = springBuildContext.getModule().getDefinition().getJavaServiceInjectByService(serviceClass.getName()); } if (injectDef != null) { String moduleId = injectDef.getSourceModuleId(); String name = injectDef.getSourceJavaServiceName(); if (moduleId != null && name != null) { component = javaServiceManager.getService(serviceClass, moduleId, name); } else { component = javaServiceManager.getService(serviceClass, moduleId); } } else { component = javaServiceManager.getService(serviceClass); } } catch (Throwable t) { throw new LilyRTException("Error assigning Java service dependency " + dependencyName + " of module " + springBuildContext.getModule().getDefinition().getId(), t); } RootBeanDefinition def = new RootBeanDefinition(ObjectFactoryBean.class); ConstructorArgumentValues args = new ConstructorArgumentValues(); args.addIndexedArgumentValue(0, serviceClass); args.addIndexedArgumentValue(1, component); def.setConstructorArgumentValues(args); def.setLazyInit(false); parserContext.getRegistry().registerBeanDefinition(id, def); return null; } }; private static final ElementProcessor EXPORT_SERVICE_PROCESSOR = new ElementProcessor() { public BeanDefinition process(Element element, ParserContext parserContext, SpringBuildContext springBuildContext) throws ClassNotFoundException { String service = element.getAttribute("service"); Class serviceClass = parserContext.getReaderContext().getBeanClassLoader().loadClass(service); String beanName = element.getAttribute("ref"); String name = element.getAttribute("name"); if (name.equals("")) { name = beanName; } springBuildContext.exportJavaService(name, serviceClass, beanName); return null; } }; private static final ElementProcessor CONF_PROCESSOR = new ElementProcessor() { public BeanDefinition process(Element element, ParserContext parserContext, SpringBuildContext springBuildContext) throws Exception { String path = element.getAttribute("path"); String expr = element.getAttribute("select"); String type = element.getAttribute("type"); String moduleId = springBuildContext.getModule().getDefinition().getId(); Conf conf = springBuildContext.getRuntime().getConfManager().getConfRegistry(moduleId).getConfiguration(path); if (expr.length() > 0) { JXPathContext context = JXPathContext.newContext(conf); Object value; try { if (type != null && type.equals("node")) { value = context.selectSingleNode(expr); if (!(value instanceof Conf)) { throw new LilyRTException("Element " + element.getTagName() + " of Spring bean config in module " + moduleId + ": configuration pointed to by expression \"" + expr + "\"" + " does not evaluate to a node."); } } else { value = String.valueOf(context.getValue(expr)); } } catch (LilyRTException e) { throw e; } catch (Exception e) { throw new LilyRTException("Element " + element.getTagName() + " of Spring bean config in module " + moduleId + ": error retrieving configuration value using expression \"" + expr + "\"" + " from configuration path \"" + path + "\".", e); } GenericBeanDefinition def = new GenericBeanDefinition(); def.setBeanClass(ObjectFactoryBean.class); ConstructorArgumentValues args = new ConstructorArgumentValues(); args.addIndexedArgumentValue(0, value instanceof Conf ? Conf.class : String.class); args.addIndexedArgumentValue(1, value); def.setConstructorArgumentValues(args); def.setLazyInit(false); return def; } else { GenericBeanDefinition def = new GenericBeanDefinition(); def.setBeanClass(ObjectFactoryBean.class); ConstructorArgumentValues args = new ConstructorArgumentValues(); args.addIndexedArgumentValue(0, Conf.class); args.addIndexedArgumentValue(1, conf); def.setConstructorArgumentValues(args); def.setLazyInit(false); return def; } } }; private static final Map<String, ElementProcessor> ELEMENT_PROCESSORS; static { ELEMENT_PROCESSORS = new HashMap<String, ElementProcessor>(); ELEMENT_PROCESSORS.put("import-service", IMPORT_SERVICE_PROCESSOR); ELEMENT_PROCESSORS.put("export-service", EXPORT_SERVICE_PROCESSOR); ELEMENT_PROCESSORS.put("module", MODULE_PROCESSOR); ELEMENT_PROCESSORS.put("conf", CONF_PROCESSOR); } }